﻿using System;

namespace Slc.Core.Entity
{
    /// <summary>
    /// OQL 条件对象，兼容老版本的OQL2对象。建议使用OQLCompare对象构造复杂的条件
    /// </summary>
    public class OQLCondition
    {
        private OQL CurrentOQL;
        private string conditionString;

        public OQLCondition(OQL oql)
        {
            CurrentOQL = oql;
            conditionString = " 1=1 ";
        }

        public string ConditionString
        {
            get { return conditionString; }
        }

        private OQLCondition subCondition(string logicType, string currFieldName, string compareType, object Value)
        {
            if (compareType == null || compareType == "")
                compareType = "=";
            else
                compareType = compareType.Trim().ToLower();

            if (compareType == "=" || compareType == ">=" || compareType == ">" || compareType == "<=" || compareType == "<" || compareType == "<>" || compareType.StartsWith("like"))
            {
                TableNameField tnf = new TableNameField();
                tnf.Entity = this.CurrentOQL.currEntity;
                tnf.Field = currFieldName;
                tnf.FieldValue = Value;
                conditionString += logicType + currFieldName + " " + compareType + " " + CurrentOQL.CreateParameter(tnf);
            }
            else if (compareType.StartsWith("is"))
            {
                string strValue = Value.ToString().ToUpper();
                if (strValue == "NULL" || strValue == "NOT NULL")
                    conditionString += logicType + currFieldName + " IS " + strValue;
                else
                    throw new FormatException("IS 条件只能是NULL或者 NOT NULL");
            }
            else
            {
                throw new Exception("比较符号必须是 =,>,>=,<,<=,<>,like,is 中的一种。");
            }
            return this;
        }

        /// <summary>
        /// 选取 与 条件
        /// </summary>
        /// <param name="field">实体对象的属性</param>
        /// <param name="compareType">SQL 比较条件，如"=","LIKE","IS" 等</param>
        /// <param name="Value">要比较的值</param>
        /// <returns>多条件表达式</returns>
        public OQLCondition AND(object field, string compareType, object Value)
        {
            string currFieldName = CurrentOQL.TakeOneStackFields().Field;
            return subCondition(" AND ", currFieldName, compareType, Value);
        }

        /// <summary>
        /// 选取 或 条件
        /// </summary>
        /// <param name="field">实体对象的属性</param>
        /// <param name="compareType">SQL 比较条件，如"=","LIKE","IS" 等</param>
        /// <param name="Value">要比较的值</param>
        /// <returns>多条件表达式</returns>
        public OQLCondition OR(object field, string compareType, object Value)
        {
            string currFieldName = CurrentOQL.TakeOneStackFields().Field;
            return subCondition(" OR  ", currFieldName, compareType, Value);

        }


        /// <summary>
        /// 选取 非 条件
        /// </summary>
        /// <param name="field">实体对象的属性</param>
        /// <param name="compareType">SQL 比较条件，如"=","LIKE","IS" 等</param>
        /// <param name="Value">要比较的值</param>
        /// <returns>多条件表达式</returns>
        public OQLCondition NOT(object field, string compareType, object Value)
        {
            string currFieldName = CurrentOQL.TakeOneStackFields().Field;
            return subCondition(" NOT ", currFieldName, compareType, Value);

        }


        /// <summary>
        /// 选取 字段 列表条件
        /// </summary>
        /// <param name="field">实体对象的属性</param>
        /// <param name="Values">值列表</param>
        /// <returns>条件表达式</returns>
        public OQLCondition IN(object field, object[] Values)
        {
            conditionString += getInCondition(field, Values, "IN ");
            return this;
        }

        /// <summary>
        /// 构造Not In查询条件
        /// </summary>
        /// <param name="field">字段</param>
        /// <param name="Values">值数组</param>
        /// <returns></returns>
        public OQLCondition NotIn(object field, object[] Values)
        {
            conditionString += getInCondition(field, Values, " NOT IN ");
            return this;
        }

        private string getInCondition(object field, object[] Values, string inType)
        {
            string currFieldName = CurrentOQL.TakeOneStackFields().Field;
            string strInTemp = string.Empty;
            string strResult = string.Empty;
            if (field == null || field.GetType() == typeof(string))
            {
                foreach (object obj in Values)
                {
                    strInTemp += "," + CurrentOQL.CreateParameter(null,obj.ToString());
                }
            }
            else if (field.GetType() == typeof(DateTime))
            {
                foreach (object obj in Values)
                {
                    strInTemp += "," + CurrentOQL.CreateParameter(null, (DateTime)obj);
                }
            }
            else
            {
                foreach (object obj in Values)
                {
                    if (obj != null)
                        strInTemp += "," + obj.ToString();
                    else
                        strInTemp += ",NULL";

                }
            }

            if (strInTemp != "")
            {
                strResult = " AND " + currFieldName + " " + inType + " (" + strInTemp.TrimStart(',') + ")";
            }
            return strResult;
        }

        /// <summary>
        /// 以另外一个OQL条件作为In的子查询
        /// </summary>
        /// <seealso cref="http://www.cnblogs.com/bluedoctor/archive/2011/02/24/1963606.html"/>
        /// <param name="field">属性字段</param>
        /// <param name="q">OQL表达式</param>
        /// <returns></returns>
        public OQLCondition IN(object field, OQL q)
        {
            return IN(field, q, true);
        }

        /// <summary>
        /// 以另外一个OQL条件作为Not In的子查询
        /// </summary>
        /// <seealso cref="http://www.cnblogs.com/bluedoctor/archive/2011/02/24/1963606.html"/>
        /// <param name="field">属性字段</param>
        /// <param name="q">OQL表达式</param>
        /// <returns></returns>
        public OQLCondition NotIn(object field, OQL q)
        {
            return IN(field, q, false);
        }

        private OQLCondition IN(object field, OQL q, bool isIn)
        {
            string inString = isIn ? " IN " : " NOT IN ";
            string childSql = q.ToString().Replace("@P", "@INP").Replace("@CP", "@INCP");
            if (q.sql_fields.IndexOf(',') > 0)
                throw new Exception("OQL 语法错误，包含在In查询中的子查询只能使用1个实体属性，请修改子查询的Select参数。");

            //２０１３．５．２７　增加替换.Replace("@CP","@INCP")，
            string currFieldName = CurrentOQL.TakeOneStackFields().Field;
            conditionString += " AND " + currFieldName + inString + "  (\r\n" + childSql + ")";

            foreach (string key in q.Parameters.Keys)
                CurrentOQL.Parameters.Add(key.Replace("@P", "@INP").Replace("@CP", "@INCP"), q.Parameters[key]);

            return this;
        }



    }
}
